3eb781fd8oRfPgH7qTh7xvgmwD6NgA tools/internal/xi_start.c
3eb781fd0Eo9K1jEFCSAVzO51i_ngg tools/internal/xi_stop.c
3f108ae2to5nHRRXfvUK7oxgjcW_yA tools/internal/xi_usage.c
+3f86be322bd0h9jG3krZFOUgCDoxZg tools/internal/xi_vif_params.c
3eb781fd7211MZsLxJSiuy7W4KnJXg tools/internal/xi_vifinit
3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
TARGETS = xi_create xi_start xi_stop xi_destroy xi_build
TARGETS += xi_phys_grant xi_phys_revoke xi_phys_probe xi_list
-TARGETS += xi_sched_global xi_sched_domain xi_usage
+TARGETS += xi_sched_global xi_sched_domain xi_usage xi_vif_params
INSTALL = $(TARGETS) xi_vifinit xi_helper
all: $(TARGETS)
--- /dev/null
+
+#include "hypervisor-ifs/dom0_ops.h"
+#include "dom0_defs.h"
+#include "mem_defs.h"
+
+static char *argv0 = "internal_domain_vif_params";
+
+int main(int argc, char **argv)
+{
+ network_op_t netop;
+ int domain, vif;
+ unsigned long credit_bytes, credit_usec;
+
+ if ( argv[0] != NULL )
+ argv0 = argv[0];
+
+ if ( (argc != 3) && (argc != 5) )
+ {
+ fprintf(stderr, "Usage: %s <domain-id> <vif-id> "
+ "[<credit-bytes> <credit-usec>]\n", argv0);
+ fprintf(stderr, "Specify <credit usec> == 0 to disable scheduling\n");
+ return 1;
+ }
+
+ domain = atol(argv[1]);
+ vif = atol(argv[2]);
+
+ if ( argc == 5 )
+ {
+ credit_bytes = atol(argv[3]);
+ credit_usec = atol(argv[4]);
+
+ netop.cmd = NETWORK_OP_VIFSETPARAMS;
+ netop.u.vif_setparams.domain = domain;
+ netop.u.vif_setparams.vif = vif;
+ netop.u.vif_setparams.credit_bytes = credit_bytes;
+ netop.u.vif_setparams.credit_usec = credit_usec;
+ if ( do_network_op(&netop) < 0 )
+ return 1;
+
+ if ( credit_usec != 0 )
+ {
+ printf("Set scheduling to %lu bytes every"
+ " %lu usecs (%2.2f Mbps)\n",
+ credit_bytes, credit_usec,
+ ((float)credit_bytes/(1024.0*1024.0/8.0)) /
+ ((float)credit_usec/1000000.0));
+ }
+ else
+ {
+ printf("Disabled rate limiting for vif\n");
+ }
+ }
+ else
+ {
+ netop.cmd = NETWORK_OP_VIFGETINFO;
+ netop.u.vif_getinfo.domain = domain;
+ netop.u.vif_getinfo.vif = vif;
+ if ( do_network_op(&netop) < 0 )
+ return 1;
+
+ printf("%lld bytes transmitted\n"
+ "%lld packets transmitted\n"
+ "%lld bytes received\n"
+ "%lld packets received\n",
+ netop.u.vif_getinfo.total_bytes_sent,
+ netop.u.vif_getinfo.total_packets_sent,
+ netop.u.vif_getinfo.total_bytes_received,
+ netop.u.vif_getinfo.total_packets_received);
+
+ if ( netop.u.vif_getinfo.credit_usec != 0 )
+ {
+ printf("Scheduling: %lu bytes every %lu usecs (%2.2f Mbps)\n",
+ netop.u.vif_getinfo.credit_bytes,
+ netop.u.vif_getinfo.credit_usec,
+ ((float)netop.u.vif_getinfo.credit_bytes/(1024.0*1024.0/8.0)) /
+ ((float)netop.u.vif_getinfo.credit_usec/1000000.0));
+ }
+ else
+ {
+ printf("Scheduling: no rate limit\n");
+ }
+ }
+
+ return 0;
+}
int main(void)
{
- unsigned char buf[208], abuf[32];
+ unsigned char buf[208];
struct sockaddr_in addr, from;
int fromlen = sizeof(from);
int len, fd = socket(PF_INET, SOCK_DGRAM, 0);
>= 0 )
{
#if 0
+ unsigned char abuf[32];
printf("%d-byte message from %s:%d --\n", len,
inet_ntop(AF_INET, &from.sin_addr, abuf, sizeof(abuf)),
ntohs(from.sin_port));
spin_lock_init(&new_vif->rx_lock);
spin_lock_init(&new_vif->tx_lock);
+ new_vif->credit_bytes = new_vif->remaining_credit = ~0UL;
+ new_vif->credit_usec = 0UL;
+ init_ac_timer(&new_vif->credit_timeout, 0);
+
if ( (p->domain == 0) && (dom_vif_idx == 0) )
{
/*
*/
int vif_getinfo(vif_getinfo_t *info)
{
- struct task_struct *p;
net_vif_t *vif;
- info->total_bytes_sent =
- info->total_bytes_received =
- info->total_packets_sent =
- info->total_packets_received = -1;
-
- if ( !(p = find_domain_by_id(info->domain)) )
- return -ENOSYS;
-
- vif = p->net_vif_list[info->vif];
-
+ vif = find_vif_by_id((info->domain << VIF_DOMAIN_SHIFT) | info->vif);
if ( vif == NULL )
- {
- put_task_struct(p);
- return -ENOSYS;
- }
+ return -ESRCH;
info->total_bytes_sent = vif->total_bytes_sent;
info->total_bytes_received = vif->total_bytes_received;
info->total_packets_sent = vif->total_packets_sent;
info->total_packets_received = vif->total_packets_received;
- put_task_struct(p);
+ info->credit_bytes = vif->credit_bytes;
+ info->credit_usec = vif->credit_usec;
+
+ put_vif(vif);
return 0;
}
+
+int vif_setparams(vif_setparams_t *params)
+{
+ net_vif_t *vif;
+
+ vif = find_vif_by_id((params->domain << VIF_DOMAIN_SHIFT) | params->vif);
+ if ( vif == NULL )
+ return -ESRCH;
+
+ /* Turning off rate limiting? */
+ if ( params->credit_usec == 0 )
+ params->credit_bytes = ~0UL;
+
+ vif->credit_bytes = vif->remaining_credit = params->credit_bytes;
+ vif->credit_usec = params->credit_usec;
+
+ put_vif(vif);
+
+ return 0;
+}
+
/* ----[ Net Rule Functions ]-----------------------------------------------*/
}
break;
+ case NETWORK_OP_VIFSETPARAMS:
+ {
+ ret = vif_setparams(&op.u.vif_setparams);
+ }
+ break;
+
default:
ret = -ENOSYS;
}
{
unsigned int domain;
unsigned int vif;
+
/* domain & vif are supplied by dom0, the rest are response fields */
long long total_bytes_sent;
long long total_bytes_received;
long long total_packets_sent;
long long total_packets_received;
+
+ /* Current scheduling parameters */
+ unsigned long credit_bytes;
+ unsigned long credit_usec;
} vif_getinfo_t;
+/*
+ * Set parameters associated with a VIF. Currently this is only scheduling
+ * parameters --- permit 'credit_bytes' to be transmitted every 'credit_usec'.
+ */
+typedef struct vif_setparams_st
+{
+ unsigned int domain;
+ unsigned int vif;
+ unsigned long credit_bytes;
+ unsigned long credit_usec;
+} vif_setparams_t;
+
/* Network trap operations and associated structure.
* This presently just handles rule insertion and deletion, but will
* evenually have code to add and remove interfaces.
#define NETWORK_OP_GETRULELIST 2
#define NETWORK_OP_VIFQUERY 3
#define NETWORK_OP_VIFGETINFO 4
+#define NETWORK_OP_VIFSETPARAMS 5
typedef struct network_op_st
{
net_rule_t net_rule;
vif_query_t vif_query;
vif_getinfo_t vif_getinfo;
+ vif_setparams_t vif_setparams;
}
u;
} network_op_t;
long long total_packets_sent;
long long total_packets_received;
+ /* Trasnmit shaping: allow 'credit_bytes' everu 'credit_usec'. */
+ unsigned long credit_bytes;
+ unsigned long credit_usec;
+ unsigned long remaining_credit;
+ struct ac_timer credit_timeout;
+
/* Miscellaneous private stuff. */
struct task_struct *domain;
unsigned int idx; /* index within domain */
return proto;
}
+static void tx_credit_callback(unsigned long data)
+{
+ net_vif_t *vif = (net_vif_t *)data;
+
+ vif->remaining_credit = vif->credit_bytes;
+
+ if ( get_tx_bufs(vif) )
+ {
+ add_to_net_schedule_list_tail(vif);
+ maybe_schedule_tx_action();
+ }
+}
static int get_tx_bufs(net_vif_t *vif)
{
unsigned short protocol;
struct sk_buff *skb;
tx_req_entry_t tx;
- int i, j, ret;
+ int i, j, ret = 0;
unsigned long flags;
if ( vif->tx_req_cons == shared_idxs->tx_req_prod )
spin_lock_irqsave(&vif->tx_lock, flags);
+ /* Currently waiting for more credit? */
+ if ( vif->remaining_credit == 0 )
+ goto out;
+
j = vif->tx_prod;
/*
continue;
}
+ /* Credit-based scheduling. */
+ if ( tx.size > vif->remaining_credit )
+ {
+ s_time_t now = NOW(), next_credit =
+ vif->credit_timeout.expires + MICROSECS(vif->credit_usec);
+ if ( next_credit <= now )
+ {
+ vif->credit_timeout.expires = now;
+ vif->remaining_credit = vif->credit_bytes;
+ }
+ else
+ {
+ vif->remaining_credit = 0;
+ vif->credit_timeout.expires = next_credit;
+ vif->credit_timeout.data = (unsigned long)vif;
+ vif->credit_timeout.function = tx_credit_callback;
+ vif->credit_timeout.cpu = smp_processor_id();
+ add_ac_timer(&vif->credit_timeout);
+ break;
+ }
+ }
+ vif->remaining_credit -= tx.size;
+
/* No crossing a page boundary as the payload mustn't fragment. */
if ( ((tx.addr & ~PAGE_MASK) + tx.size) >= PAGE_SIZE )
{
*/
smp_mb();
- if ( (vif->tx_req_cons = i) != shared_idxs->tx_req_prod )
+ if ( ((vif->tx_req_cons = i) != shared_idxs->tx_req_prod) &&
+ (vif->remaining_credit != 0) )
goto again;
if ( (ret = (vif->tx_prod != j)) )
vif->tx_prod = j;
+ out:
spin_unlock_irqrestore(&vif->tx_lock, flags);
return ret;